package com.erp.ueditor.upload;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.ArrayUtils;

import com.alibaba.appengine.api.store.StoreService;
import com.alibaba.appengine.api.store.StoreServiceFactory;
import com.aliyun.openservices.ClientException;
import com.aliyun.openservices.ServiceException;
import com.aliyun.openservices.oss.OSSClient;
import com.aliyun.openservices.oss.OSSErrorCode;
import com.aliyun.openservices.oss.OSSException;
import com.aliyun.openservices.oss.model.CannedAccessControlList;
import com.aliyun.openservices.oss.model.ObjectMetadata;
import com.erp.ueditor.ConfigManager;
import com.erp.ueditor.define.AppInfo;
import com.erp.ueditor.define.BaseState;
import com.erp.ueditor.define.State;

public class StorageManager {
	public static final int BUFFER_SIZE = 8192;

	public StorageManager() {
	}

	public static State saveBinaryFile(byte[] data, String path) {
		File file = new File(path);

		State state = valid(file);

		if (!state.isSuccess()) {
			return state;
		}

		try {
			BufferedOutputStream bos = new BufferedOutputStream(
					new FileOutputStream(file));
			bos.write(data);
			bos.flush();
			bos.close();
		} catch (IOException ioe) {
			return new BaseState(false, AppInfo.IO_ERROR);
		}

		state = new BaseState(true, file.getAbsolutePath());
		state.putInfo("size", data.length);
		state.putInfo("title", file.getName());
		return state;
	}

	public static State saveFileByInputStream(InputStream is, String path,
			long maxSize) {
		State state = null;

		File tmpFile = getTmpFile();

		byte[] dataBuf = new byte[2048];
		BufferedInputStream bis = new BufferedInputStream(is,
				StorageManager.BUFFER_SIZE);

		try {
			BufferedOutputStream bos = new BufferedOutputStream(
					new FileOutputStream(tmpFile), StorageManager.BUFFER_SIZE);

			int count = 0;
			while ((count = bis.read(dataBuf)) != -1) {
				bos.write(dataBuf, 0, count);
			}
			bos.flush();
			bos.close();

			if (tmpFile.length() > maxSize) {
				tmpFile.delete();
				return new BaseState(false, AppInfo.MAX_SIZE);
			}

			state = saveTmpFile(tmpFile, path);

			if (!state.isSuccess()) {
				tmpFile.delete();
			}

			return state;

		} catch (IOException e) {
		}
		return new BaseState(false, AppInfo.IO_ERROR);
	}

	/**
	 * uEditor的保存方式
	 * 
	 * @param is
	 * @param path
	 * @return
	 */
	public static State saveFileByInputStream(InputStream is, String path) {
		State state = null;

		File tmpFile = getTmpFile();

		byte[] dataBuf = new byte[2048];
		BufferedInputStream bis = new BufferedInputStream(is,
				StorageManager.BUFFER_SIZE);

		try {
			BufferedOutputStream bos = new BufferedOutputStream(
					new FileOutputStream(tmpFile), StorageManager.BUFFER_SIZE);

			int count = 0;
			while ((count = bis.read(dataBuf)) != -1) {
				bos.write(dataBuf, 0, count);
			}

			byte[] temp = new byte[0];
			while (bis.read(dataBuf) != -1) {
				temp = ArrayUtils.addAll(temp, dataBuf);
			}
			bos.write(dataBuf, 0, temp.length);

			bos.flush();
			bos.close();

			state = saveTmpFile(tmpFile, path);

			if (!state.isSuccess()) {
				tmpFile.delete();
			}

			return state;
		} catch (IOException e) {
		}
		return new BaseState(false, AppInfo.IO_ERROR);
	}

	/**
	 * ACE提供的简单存储服务
	 * 
	 * @param is
	 * @return
	 */
	public static State saveFile2Storage(InputStream is, String path) {
		State state = new BaseState(true);

		byte[] dataBuf = new byte[2048];
		BufferedInputStream bis = new BufferedInputStream(is,
				StorageManager.BUFFER_SIZE);

		try {
			byte[] temp = new byte[0];
			while (bis.read(dataBuf) != -1) {
				temp = ArrayUtils.addAll(temp, dataBuf);
			}
			StoreService storeService = StoreServiceFactory
					.getStoreService("upload");
			storeService.saveBinaryFile(temp,
					path.substring(path.lastIndexOf("/")));
			state.putInfo("size", temp.length);
			state.putInfo("title", "");

		} catch (Exception e) {
			e.printStackTrace();
		}

		return state;
	}

	private static File getTmpFile() {
		File tmpDir = FileUtils.getTempDirectory();
		String tmpFileName = (Math.random() * 10000 + "").replace(".", "");
		return new File(tmpDir, tmpFileName);
	}

	private static State saveTmpFile(File tmpFile, String path) {
		State state = null;
		File targetFile = new File(path);

		if (targetFile.canWrite()) {
			return new BaseState(false, AppInfo.PERMISSION_DENIED);
		}
		try {
			FileUtils.moveFile(tmpFile, targetFile);
		} catch (IOException e) {
			return new BaseState(false, AppInfo.IO_ERROR);
		}

		state = new BaseState(true);
		state.putInfo("size", targetFile.length());
		state.putInfo("title", targetFile.getName());

		return state;
	}

	private static State valid(File file) {
		File parentPath = file.getParentFile();

		if ((!parentPath.exists()) && (!parentPath.mkdirs())) {
			return new BaseState(false, AppInfo.FAILED_CREATE_FILE);
		}

		if (!parentPath.canWrite()) {
			return new BaseState(false, AppInfo.PERMISSION_DENIED);
		}

		return new BaseState(true);
	}

	/**
	 * 保存文件到OSS
	 * 
	 * @param bucketName
	 *            根目录bucket的名称
	 * @param saveToPath
	 *            保存的目标路径（相对于根目录）
	 * @param maxSize
	 *            文件大小
	 * @param is
	 *            文件流
	 * @return
	 * @throws OSSException
	 * @throws ClientException
	 * @throws FileNotFoundException
	 */
	public static State saveFile2OSS(String bucketName, String saveToPath,
			InputStream is) {

		BaseState state = new BaseState(true);

		// 使用默认的OSS服务器地址创建OSSClient对象。
		OSSClient client = new OSSClient(ConfigManager.ACCESS_ID,
				ConfigManager.ACCESS_KEY);

		ensureBucket(client, bucketName);
		setBucketPublicReadable(client, bucketName);

		ObjectMetadata objectMeta = new ObjectMetadata();

		long fileLength = 0;
		File tempFile = getFileFromFileInputStream(is);
		fileLength = tempFile.length();
		InputStream input = null;

		try {
			input = new FileInputStream(tempFile);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		objectMeta.setContentLength(fileLength);
		// 可以在metadata中标记文件类型
		objectMeta.setContentType("image/jpeg");

		client.putObject(bucketName, saveToPath, input, objectMeta);
		tempFile.delete();
		
		state.putInfo("size", fileLength);
		state.putInfo("title",
				saveToPath.substring(saveToPath.lastIndexOf("/")));

		return state;
	}

	/**
	 * 创建一个Bucket（如果已经存在，则忽略错误码）
	 * 
	 * @param client
	 * @param bucketName
	 * @throws OSSException
	 * @throws ClientException
	 */
	private static void ensureBucket(OSSClient client, String bucketName)
			throws OSSException, ClientException {

		try {
			// 创建bucket
			client.createBucket(bucketName);
		} catch (ServiceException e) {
			if (!OSSErrorCode.BUCKES_ALREADY_EXISTS.equals(e.getErrorCode())) {
				// 如果Bucket已经存在，则忽略
				System.out.println("Bucket" + bucketName + "已经存在");
				throw e;
			}
		}
	}

	/**
	 * 把Bucket设置为所有人可读
	 * 
	 * @param client
	 * @param bucketName
	 * @throws OSSException
	 * @throws ClientException
	 */
	private static void setBucketPublicReadable(OSSClient client,
			String bucketName) throws OSSException, ClientException {
		// 创建bucket
		client.createBucket(bucketName);

		// 设置bucket的访问权限，public-read-write权限
		client.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
	}

	/**
	 * 从文件流获取文件
	 * 
	 * @param is
	 * @throws Exception
	 */
	private static File getFileFromFileInputStream(InputStream is) {
		File tmpFile = getTmpFile();
		byte[] dataBuf = new byte[2048];
		BufferedInputStream bis = new BufferedInputStream(is);

		BufferedOutputStream bos = null;
		try {
			bos = new BufferedOutputStream(new FileOutputStream(tmpFile));

			int count = 0;
			while ((count = bis.read(dataBuf)) != -1) {
				bos.write(dataBuf, 0, count);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				bos.flush();
				bos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return tmpFile;
	}

}
